package club.kingyin.kyblogprogateway.filter;

import club.kingyin.commons.clients.UserClient;
import club.kingyin.commons.constant.AuthorizeConstant;
import club.kingyin.commons.constant.LogConstant;
import club.kingyin.commons.entity.user.User;
import club.kingyin.commons.enums.BlogEnum;
import club.kingyin.commons.response.Result;
import club.kingyin.commons.response.ResultCode;
import club.kingyin.commons.utils.RequestUtils;
import club.kingyin.commons.utils.ResponseUtils;
import club.kingyin.easytoken.core.EasyToken;
import club.kingyin.pathfilter.core.PathFilter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

// 权限验证 跳过无需验证的路径，在配置文件设置
@Component
@Slf4j
public class AuthorizeFilter implements GlobalFilter, Ordered {

    @Autowired
    private EasyToken easyToken;
    @Autowired
    private PathFilter pathFilter;

    @Autowired
    private UserClient userClient;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @SneakyThrows
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        RequestPath path = request.getPath();
        boolean next = false;
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst("KY-TOKEN");
        User current = null;
        if (pathFilter.intercept(path.value())) {
            log.info("{} 跳过认证", path.value());
            ServerHttpRequest.Builder header = request.mutate()
                    .header(AuthorizeConstant.ROLE, URLEncoder.encode(BlogEnum.USER.getDesc(), "UTF8"));
            if (token != null && (current = easyToken.deToken(token, User.class)).getId() != null) {
                header.header(AuthorizeConstant.ID, String.valueOf(current.getId()));
            } else {
                header.header(AuthorizeConstant.ID,"0");
            }
            // 跳过验证
            return chain.filter(exchange.mutate().request(header.build()).build());
        }

        ServerHttpRequest authorizeHeader = null;
        // 验证token
        try {
            if (token != null) {
                String res = redisTemplate.opsForValue().get(token);
                if (res != null && (current = JSONObject.parseObject(res,User.class)).getId() != null) {
                    next = true;
                    // 登出 删除token
                    if ("/user/logout".equals(path.value()) && Objects.equals(exchange.getRequest().getMethod(), HttpMethod.POST)) {
                        Boolean t = redisTemplate.delete(token);
                        Boolean u = redisTemplate.delete(current.getUsername());
                        exchange.getResponse().setStatusCode(HttpStatus.OK);
                        return exchange.getResponse().setComplete();
                    }
                } else {
                    // token失效 重新验证
                    if ((current = easyToken.deToken(token, User.class)).getId() != null) {
                        easyToken.deToken(token, User.class);
                        System.out.println(current);
                        redisTemplate.opsForValue().set(current.getUsername(), token,1, TimeUnit.DAYS);
                        String user = JSON.toJSONString(current);
                        redisTemplate.opsForValue().set(token,user,1,TimeUnit.DAYS);
                    }
                }
                if (current.getId() == null) {
                    next = false;
                } else {
                    if (current.getRole() == BlogEnum.ROOT) {
                    }
                    if (current.getTitled() == null) {
                        // 旧版本的Token，更新信息
                        Result result = userClient.getTitledById(current.getId());
                        current.setTitled((long) ((int) result.getData()));
                        redisTemplate.opsForValue().set(token,JSON.toJSONString(current),7,TimeUnit.DAYS);
                    }
                    // 封号
                    else if (current.getTitled() < 0 || current.getTitled() > System.currentTimeMillis()) {
                        DataBuffer responseBuffer = ResponseUtils.createResponseBuffer(exchange.getResponse(), Result.failR("由于您的账号存在违规操作已被封号，将于" + ResponseUtils.stampToTime(current.getTitled()) + "解封,申诉请联系QQ：578145931"));
                        return exchange.getResponse().writeWith(Mono.just(responseBuffer));
                    }
                    authorizeHeader = request.mutate()
                            .header(AuthorizeConstant.USERNAME, URLEncoder.encode(current.getUsername(),"UTF8"))
                            .header(AuthorizeConstant.NICKNAME,  URLEncoder.encode(current.getNickname(),"UTF8"))
                            .header(AuthorizeConstant.AVATAR, URLEncoder.encode(current.getAvater(),"UTF8"))
                            .header(AuthorizeConstant.ROLE,  URLEncoder.encode(current.getRole().getDesc(),"UTF8"))
                            .header(AuthorizeConstant.ID, String.valueOf(current.getId()))
                            .build();
                }

            }
        } catch (Exception e) {
            next = false;
            e.printStackTrace();
        }
        if (next) {
            // 权限验证成功
            return chain.filter(exchange.mutate().request(authorizeHeader).build());
        }

        // 权限验证失败
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -2;
    }
}
